#ifndef __RT_RESULT2_H
#define __RT_RESULT2_H

#include <stdexcept>
#include <type_traits>
#include <variant>

namespace rt {

template <typename T = void> class Result2 {

public:
    struct None {};
    struct Unit {};

    using TYPE = std::conditional_t<std::is_void_v<T>, Unit, T>;

    inline operator bool() const noexcept {
        return !std::holds_alternative<None>(m_value);
    }

    template <typename U = T>
    std::enable_if_t<std::is_void_v<U>, void> set_value() {
        m_value = Unit();
    }

    template <typename U = T>
    std::enable_if_t<!std::is_void_v<U>, void> set_value(TYPE &&value) {
        m_value = std::forward<U>(value);
    }

    void set_err(const std::exception_ptr &err) { m_value = err; }

    T get() {
        if (std::holds_alternative<None>(m_value)) {
            throw std::runtime_error("result is none");
        }
        if (std::holds_alternative<std::exception_ptr>(m_value)) {
            std::rethrow_exception(std::get<std::exception_ptr>(m_value));
        }
        if constexpr (!std::is_void_v<T>) {
            T value = std::move(std::get<T>(m_value));
            return value;
        }
    }

private:
    std::variant<None, TYPE, std::exception_ptr> m_value;
};

} // namespace rt

#endif
